package com.thy.service.impl;


import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hospital.common.base.PageResult;
import com.hospital.common.base.ThreadAttributes;
import com.hospital.common.dto.audit.module.BanDto;
import com.hospital.common.dto.audit.module.UnBanDto;
import com.hospital.common.dto.audit.module.UserDto;
import com.hospital.common.pojo.TBanned;
import com.hospital.common.utils.ThreadLocalUtils;
import com.hospital.common.vo.audit.module.SectionVo;
import com.hospital.common.vo.audit.module.UserVo;
import com.thy.aop.LogAction;
import com.thy.aop.LogTargetType;
import com.thy.mapper.TBannedMapper;
import com.thy.service.TBannedService;
import com.thy.utils.AuitLogUtil;
import com.thy.utils.JsonUtil;
import com.thy.utils.MessageUtil;
import com.thy.utils.ObjectConvertUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 封禁列表 服务实现类
 * </p>
 *
 * @author author
 * @since 2025-09-26
 */
@Service
public class TBannedServiceImpl extends ServiceImpl<TBannedMapper, TBanned> implements TBannedService {
    @Autowired
    private TBannedMapper tBannedMapper;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public Integer getBannedStatus(Long userId,Long sectionId) {
        String key = "ban:" + userId + ":" + sectionId;
        Boolean hasKey = stringRedisTemplate.hasKey(key);
        if (!hasKey) {
            return 0;//正常
        }
        return 1;//封禁
    }

    @Override
    public PageResult<UserVo> getAllUsers(UserDto userDto) {
        Page<UserVo> page = new Page<>(userDto.getPageNum(), userDto.getPageSize());
        IPage<UserVo> users = tBannedMapper.getAllUsers(page,userDto);
        //判断是否被封禁
        for (UserVo userVo : users.getRecords()) {
            Integer isBanned = getBannedStatus(userVo.getUserId(), userVo.getSectionId());//0正常 1封禁
            userVo.setIsBanned(isBanned);
        }
        return new PageResult<>(users.getTotal(), users.getRecords());
    }

    @Override
    public Integer ban(BanDto banDto) {
        try {
            String key = "ban:" + banDto.getBannedId() + ":" + banDto.getBannedSectionId();
            // 将BanDto对象转换为JSON字符串存储
            String jsonBanDto = JsonUtil.toJsonString(banDto);
            stringRedisTemplate.opsForValue().set(key, jsonBanDto);
            // 根据bannedStartTime和bannedDays设置精确的过期时间
            if (banDto.getBannedDays() != null && banDto.getBannedDays() > 0) {
                LocalDateTime startTime = banDto.getBannedStartTime();
                if (startTime != null) {
                    // 计算精确的过期时间点
                    LocalDateTime expireTime = startTime.plusDays(banDto.getBannedDays());
                    // 计算距离现在还有多长时间过期
                    Duration duration = Duration.between(LocalDateTime.now(), expireTime);

                    if (duration.getSeconds() > 0) {
                        // 设置精确的过期时间（转换为秒）
                        stringRedisTemplate.expire(key, duration.getSeconds(), TimeUnit.SECONDS);
                    } else {
                        // 如果已经过了过期时间，则删除这个键
                        stringRedisTemplate.delete(key);
                    }
                } else {
                    // 如果没有设置开始时间，默认从现在开始计算
                    stringRedisTemplate.expire(key, banDto.getBannedDays(), TimeUnit.DAYS);
                }
            }
            // 获取板块名称
            String sectionName = tBannedMapper.getSection(banDto.getBannedSectionId());
            // 发送消息给被封禁用户
            String message = "从"+banDto.getBannedStartTime()+"起，您在"+sectionName+"板块将被封禁，封禁时间为："+
                    (banDto.getBannedDays()==-1?"永久封禁":banDto.getBannedDays()+"天")+"，封禁原因："+banDto.getBannedReason()
                    +"若需申诉，请联系管理员！";
            MessageUtil.sendMessage(banDto.getBannerId(),banDto.getBannedId(), message);
            // 记录日志
            AuitLogUtil.log(banDto.getBannerId(), LogAction.BAN.getId(), banDto.getBannedId(), LogTargetType.REGULAR_USER.getId());
            return 1; // 封禁成功
        } catch (Exception e) {
            return 0; // 封禁失败
        }
    }

    @Override
    public Integer unban(UnBanDto unBanDto) {
        ThreadAttributes threadAttributes = ThreadLocalUtils.get();
        Long userId = threadAttributes.getUserId();
        String key = "ban:" + unBanDto.getBannedId() + ":" + unBanDto.getBannedSectionId();
        // 直接删除key，delete方法会返回是否删除成功
        Boolean deleted = stringRedisTemplate.delete(key);
        if (deleted) {
            //发送消息给被解封用户
            String sectionName = tBannedMapper.getSection(unBanDto.getBannedSectionId());
            String message = "您已从"+sectionName+"板块中解除封禁！";
            MessageUtil.sendMessage(userId,unBanDto.getBannedId(), message);
           // 记录日志
            AuitLogUtil.log(userId, LogAction.UNBAN.getId(), unBanDto.getBannedId(), LogTargetType.REGULAR_USER.getId());
            return 0; // 解封成功
        } else {
            return 1; // 解封失败(可能key不存在)
        }
    }

    @Override
    public List<SectionVo> getAllSection() {
        return tBannedMapper.getAllSection();
    }

    //定时任务：将redis中的数据存进数据库
    @Scheduled(cron = "00 00 23 * * ?")//每天23:00执行
    public void saveBannedDataToDatabase() {
        //清空数据库
        tBannedMapper.deleteAll();
        // 获取所有键值对
        stringRedisTemplate.opsForHash().entries("ban:*").forEach((key, value) -> {
            // 将键值对转换为BanDto对象
            BanDto banDto = JsonUtil.fromJsonString(value.toString(), BanDto.class);
            // 将BanDto对象转换为TBanned对象
            TBanned tBanned = ObjectConvertUtil.copyProperties(banDto, TBanned.class);
            //插入数据库
            tBannedMapper.insert(tBanned);
        });
    }
}
